#pragma once
#include"requestor.hpp"
namespace bitRPC{
    namespace client{
        class Provider{
            public:
                using ptr=std::shared_ptr<Provider>;
                Provider(const Requestor::ptr &requestor) : _requestor(requestor){}
                bool Registry(const BaseConnection::ptr &con,std::string method,Address& host)
                {
                    auto  msg_req=MessageFactory::create<ServiceReqest>();
                    msg_req->setMType(MType::REQ_SERVICE);
                    msg_req->setId(UUID::uuid());
                    msg_req->setMethod(method);
                    msg_req->setHost(host);
                    msg_req->setOptype(ServiceOptype::SERVICE_REGISTER);
                    BaseMessage::ptr msg_rsp;
                    bool ret=_requestor->send(con,msg_req,msg_rsp);
                    auto msg=std::dynamic_pointer_cast<ServiceResponse>(msg_rsp);
                    if(ret==false)
                    {
                        ELOG("%s 服务注册失败",method.c_str());
                        return false;
                    }
                    if(msg.get()==nullptr)
                    {
                        ELOG("服务响应向下类型转换失败");
                        return false;
                    }
                    if(msg->rcode()!=Rcode::RCODE_OK)
                    {
                        ELOG("服务注册失败，原因：%s",errReason(msg->rcode()));
                        return false;
                    }
                    return true;
                }
            private:
                Requestor::ptr _requestor;
        };
        class  MethodHost{
            public:
                using ptr=std::shared_ptr<MethodHost>;
                MethodHost( std::vector<Address>& hosts):_host(hosts)
                ,_idx(0)
                {}
                void appendAddress(const Address& host)
                {
                    //中途收到服务上线请求后被调用
                    std::unique_lock<std::mutex> lock(_mutex);
                    _host.push_back(host);
                    
                }
                Address chooseHost()
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    return _host[_idx];
                }
                void removeHost(const Address& host)
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    for(auto it=_host.begin();it!=_host.end();++it)
                    {
                        if(*it==host)
                        {
                            _host.erase(it);
                            break;
                        }
                    }
                }
                bool empty()
                {
                    return _host.empty();
                }
            private:
                std::mutex _mutex;
                std::vector<Address> _host;
                size_t _idx;
        };
        class  Discoverer{
            public:
                using offlineCallback=std::function<void(const Address)>;
                using ptr=std::shared_ptr<Discoverer>;
                Discoverer(const Requestor::ptr& requstor,const offlineCallback& offline_callback):_requestor(requstor)
                ,_offline_callback(offline_callback)
                {}
                bool serviceDiscovery(const BaseConnection::ptr conn, const std::string &method,Address& host)
                {
                    {
                        //当前所保管的提供者信息存在，则直接返回地址
                        std::unique_lock<std::mutex> lock(_mutex);
                        auto it = _method_host.find(method);
                        if (it != _method_host.end()) {
                            if (it->second->empty() == false) {
                                host = it->second->chooseHost();
                                return true;
                            }
                        }
                    }
                    //当前服务的提供者为空
                    auto msg_req = MessageFactory::create<ServiceReqest>();
                    msg_req->setId(UUID::uuid());
                    msg_req->setMType(MType::REQ_SERVICE);
                    msg_req->setMethod(method);
                    msg_req->setOptype(ServiceOptype::SERVICE_DISCOVERY);
                    BaseMessage::ptr msg_rsp;
                    _requestor->send(conn,msg_req,msg_rsp);
                    bool ret = _requestor->send(conn, msg_req, msg_rsp);
                    if (ret == false) {
                        ELOG("服务发现失败！");
                        return false;
                    }
                    auto service_rsp = std::dynamic_pointer_cast<ServiceResponse>(msg_rsp);
                    if (!service_rsp) {
                        ELOG("服务发现失败！响应类型转换失败！");
                        return false;
                    }
                    if (service_rsp->rcode() != Rcode::RCODE_OK) {
                        ELOG("服务发现失败！%s", errReason(service_rsp->rcode()).c_str());
                        return false;
                    }
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto method_host = std::make_shared<MethodHost>(service_rsp->hosts());
                    if (method_host->empty()) {
                        ELOG("%s 服务发现失败！没有能够提供服务的主机！", method.c_str());
                        return false;
                    }
                    host = method_host->chooseHost();
                    _method_host[method] = method_host;
                    return true;

                } 
                //是给dispatcher模块进行服务上线下线请求处理的回调函数
                void onServiceRequest(const BaseConnection::ptr& conn,ServiceReqest::ptr& msg)
                {
                    // 判断是上线还是下线，都不是就不用处理了
                    auto optype = msg->optype();
                    std::unique_lock<std::mutex> lock(_mutex);
                    if(optype==ServiceOptype::SERVICE_ONLINE)
                    {
                        // 服务上线
                        auto host=_method_host.find(msg->method());
                        if(host==_method_host.end())
                        {
                            //没找到
                            auto method_host=std::make_shared<MethodHost>();
                            method_host->appendAddress(msg->host());
                            _method_host[msg->method()]=method_host;
                        }
                        else{
                            host->second->appendAddress(msg->host());
                        }
                    }else if(optype==ServiceOptype::SERVICE_OFFLINE)
                    {
                        //下线通知;找到MthodHOst从其中删除一个主机地址
                        auto it=_method_host.find(msg->method());
                        if(it==_method_host.end())
                        {
                            return ;
                        }else{
                            it->second->removeHost(msg->host());
                            _offline_callback(msg->host());
                        }
                    }


                }
            private:
                offlineCallback _offline_callback;
                std::mutex _mutex;
                std::unordered_map<std::string,MethodHost::ptr> _method_host;
                Requestor::ptr _requestor;
        };
    }
}